import { memo, useState, useRef, useEffect } from "react"
import {
  BarControl,
  BarOperator,
  BarPlayerInfo,
  PlayerBarWrapper
} from "./style"
import { Link } from "react-router-dom"
import { Slider, message } from "antd"
import { useAppDispatch, useAppSelector } from "@/store"
import { formatTime, getImageSize } from "@/utils/format"
import { shallowEqual } from "react-redux"
import { getSongPlayUrl } from "@/utils/handle-player"
import {
  changeLyricIndexAction,
  changeMusicAction,
  changePlayModeAction
} from "@/store/features/player"
import type { ReactNode, FC } from "react"

interface IProps {
  children?: ReactNode
}

const AppPlayerBar: FC<IProps> = () => {
  const [isPlaying, setIsPlaying] = useState(false)
  const [progress, setProgress] = useState(0)
  const [duration, setDuration] = useState(0)
  const [currentTime, setCurrentTime] = useState(0)
  const [isSliding, setIsSliding] = useState(false)
  const audioRef = useRef<HTMLAudioElement>(null)

  const { currentSong, lyrics, lyricIndex, playMode } = useAppSelector(
    (state) => ({
      currentSong: state.player.currentSong,
      lyrics: state.player.lyrics,
      lyricIndex: state.player.lyricIndex,
      playMode: state.player.playMode
    }),
    shallowEqual
  )

  const dispatch = useAppDispatch()

  /** 组件内的副作用操作 */
  useEffect(() => {
    // 1.播放音乐
    audioRef.current!.src = getSongPlayUrl(currentSong.id)
    audioRef.current
      ?.play()
      .then(() => {
        setIsPlaying(true)
        console.log("歌曲播放成功")
      })
      .catch((err) => {
        setIsPlaying(false)
        console.log("歌曲播放失败:", err)
      })

    // 2.设置歌曲的总时长
    setDuration(currentSong.dt)
  }, [currentSong])

  // 音乐播放进度处理
  const handleTimeUpdate = () => {
    // 1.获取当前的播放时间
    const currentTime = audioRef.current!.currentTime * 1000

    // 2.判断是否处于拖拽状态
    if (!isSliding) {
      // 3.计算播放进度
      const progress = (currentTime / duration) * 100
      // 4.更新播放进度
      setProgress(progress)
      // 5.更新当前播放时间
      setCurrentTime(currentTime)
    }

    // 默认是最后一句歌词
    let index = lyrics.length - 1
    for (let i = 0; i < lyrics.length; i++) {
      const lyric = lyrics[i]
      if (lyric.time > currentTime) {
        index = i - 1
        break
      }
    }

    // 匹配上对应歌词的index
    if (lyricIndex === index || index === -1) return
    dispatch(changeLyricIndexAction(index))
    message.open({
      content: lyrics[index].text,
      key: "lyric",
      duration: 0
    })
  }

  // 音乐播放结束处理
  const handleTimeEnded = () => {
    if (playMode === 2) {
      // 单曲循环
      audioRef.current!.currentTime = 0
      audioRef.current?.play()
    } else {
      // 切换到下一首
      handleChangeMusic(true)
    }
  }

  // 播放/暂停
  const handlePlayBtnClick = () => {
    // 1.控制播放器的播放/暂停
    if (isPlaying) {
      audioRef.current?.pause()
    } else {
      audioRef.current?.play().catch(() => setIsPlaying(false))
    }

    // 2.改变isPlaying的状态
    setIsPlaying(!isPlaying)
  }

  // 当 Slider 的值发生改变时，会触发 onChange 事件，并把改变后的值作为参数传入
  const handleSliderChange = (value: number) => {
    // 目前处于拖拽状态
    setIsSliding(true)

    // 设置播放进度
    setProgress(value)

    // 设置播放时间
    const currentTime = (value / 100) * duration
    setCurrentTime(currentTime)
  }

  // 与 mouseup 和 keyup 触发时机一致，把当前值作为参数传入
  const handleSliderChangeComplete = (value: number) => {
    // 1. 获取点击位置的时间
    const currentTime = (value / 100) * duration

    // 2. 设置当前播放的时间
    audioRef.current!.currentTime = currentTime / 1000

    // 3. 设置 currentTime / progress
    setCurrentTime(currentTime)
    setProgress(value)
    setIsSliding(false)
  }

  // 播放模式的切换
  const handleChangePlayMode = () => {
    let newPlayMode = playMode + 1
    if (newPlayMode > 2) {
      newPlayMode = 0
    }
    dispatch(changePlayModeAction(newPlayMode))
  }

  // 切换歌曲
  const handleChangeMusic = (isNext: boolean) => {
    dispatch(changeMusicAction(isNext))
  }

  return (
    <PlayerBarWrapper className="sprite_playbar">
      <div className="content wrap-v2">
        <BarControl isPlaying={isPlaying}>
          <button
            className="btn sprite_playbar prev"
            onClick={() => handleChangeMusic(false)}
          ></button>
          <button
            className="btn sprite_playbar play"
            onClick={handlePlayBtnClick}
          ></button>
          <button
            className="btn sprite_playbar next"
            onClick={() => handleChangeMusic(true)}
          ></button>
        </BarControl>
        <BarPlayerInfo>
          <Link to="/player">
            <img
              className="image"
              src={getImageSize(currentSong?.al?.picUrl, 80)}
              alt=""
            />
          </Link>
          <div className="info">
            <div className="song">
              <span className="song-name">{currentSong?.name}</span>
              <span className="singer-name">{currentSong?.ar?.[0]?.name}</span>
            </div>
            <div className="progress">
              <Slider
                step={0.5}
                value={progress}
                tooltip={{ formatter: null }}
                onChange={handleSliderChange}
                onChangeComplete={handleSliderChangeComplete}
              />
              <div className="time">
                <span className="current">{formatTime(currentTime)}</span>
                <span className="divider">/</span>
                <span className="duration">{formatTime(duration)}</span>
              </div>
            </div>
          </div>
        </BarPlayerInfo>
        <BarOperator playMode={playMode}>
          <div className="left">
            <button className="btn pip"></button>
            <button className="btn sprite_playbar favor"></button>
            <button className="btn sprite_playbar share"></button>
          </div>
          <div className="right sprite_playbar">
            <button className="btn sprite_playbar volume"></button>
            <button
              className="btn sprite_playbar loop"
              onClick={handleChangePlayMode}
            ></button>
            <button className="btn sprite_playbar playlist"></button>
          </div>
        </BarOperator>
      </div>
      <audio
        ref={audioRef}
        onTimeUpdate={handleTimeUpdate}
        onEnded={handleTimeEnded}
      />
    </PlayerBarWrapper>
  )
}

export default memo(AppPlayerBar)
